#ifndef PROTOCOL_H
#define PROTOCOL_H

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdint.h>
#include <stddef.h>
#include "public.h"
/* 最大帧数据长度 */
#define PROTOCOL_MAX_DATA_LEN 1000

/* 帧格式相关常量 */
#define PROTOCOL_FRAME_HEAD1 0xBF
#define PROTOCOL_FRAME_HEAD2 0xBA
#define PROTOCOL_FRAME_TAIL1 0xEA
#define PROTOCOL_FRAME_TAIL2 0xEF

    /* 协议栈状态机状态 */
    typedef enum
    {
        PROTO_STATE_IDLE = 0,
        PROTO_STATE_HEAD1,
        PROTO_STATE_HEAD2,
        PROTO_STATE_EXEC0,
        PROTO_STATE_EXEC1,
        PROTO_STATE_MOD0,
        PROTO_STATE_MOD1,
        PROTO_STATE_LEN0,
        PROTO_STATE_LEN1,
        PROTO_STATE_DATA,
        PROTO_STATE_CHECK,
        PROTO_STATE_TAIL1,
        PROTO_STATE_TAIL2
    } protocol_state_t;

    /* 协议栈实例结构体 可自由实现uart can等*/

    typedef struct protocol_ctx
    {
        // 状态机
        void *user_data; // 用户自定义通讯实例数据
        int (*send_bytes)(const uint8_t *data, size_t len);
        int (*recv_bytes)(uint8_t *data, size_t len);
        uint16_t data_cnt;
        protocol_state_t state;
        uint8_t check;
        uint16_t exec_code;
        uint16_t module_id;
        uint16_t data_len;
        uint8_t data[PROTOCOL_MAX_DATA_LEN];

    } _protocol_ctx, *protocol_ctx_t;

    typedef struct protocol_frame
    {
        _protocol_ctx ctx;
        uint16_t exec_code;
        uint16_t module_id;
        uint16_t cmd_code;
        struct
        {
            uint16_t para_len : 10; // data 域中 参数长度
            uint16_t state_len : 6; // data 域中 状态长度
        } status_code;
        uint8_t *data;
    } _protocol_frame, *protocol_frame_t;

    void protocol_init(protocol_ctx_t ctx);

    // 协议栈实例接收解析进程，获取枕头后，
    // 建议一次性 exec_code module_id data_len ,然后根据data_len 读取data[]数据,最后校验check_sum
    void protocol_input_process(protocol_ctx_t ctx);
    // 解析后，直接调用这个 传入protocol_ctx_t，应用程序可以获取到
    // _protocol_frame 结构体，可以直接使用其中的数据,protocol_on_frame实现由用户程序实现

    void protocol_on_frame(_protocol_frame *frame);

    // 在模块内部定义一个共同的cache_buffer，用于在以下两个组装数据帧，
    void protocol_result(protocol_frame_t frame, uint8_t *data, size_t len);
    void protocol_report(protocol_frame_t frame, uint8_t *data, size_t len);

typedef struct app_server
{
    uint16_t server_cmd;
    void (*server)(_protocol_frame *frame);
} _app_server, *app_server_t;


#define APP_SERVER(cmd, func) \
    RT_USED const _app_server __attribute__((section("app_server$f"))) _app_server_##func  = {cmd, func}

#ifdef __cplusplus
}
#endif
#endif 